#!/usr/bin/env python
# -*- coding: utf-8 -*-

from define import DEFSTOCK
from define import INIT_AMOUNT
from define import TRADER_LOW
from define import TRADER_HIGH
from define import TRADE_STATE_S
from define import TRADE_STATE_W
from define import TRADE_STATE_F
from define import TRADE_STATE_A
from define import HOST
from define import PORT
from define import TRADER_NUMBER
from define import TRADE_TIME_LOW
from define import TRADE_TIME_HIGH

import stock
import os
import socket
import time
import logging
import threading
import random
import errno
import sys
import uuid


class TradeRequest(object):
    def __init__(self, trader=None, action=None, stock=None):
        object.__init__(self)

        # Every value is stored in string
        ''' States of a request in queue:
        N - New
        D - Done
        I - Invalid
        Initial state of a request is 'N'
        '''
        self.trader = trader
        self.stock = stock
        self.action  = action
        self.state = 'N'

    def __str__(self):
        return "%s-%s-%s" % (self.trader.tid, self.action, self.stock)

    def is_valid(self, req):
        if self.stock.name == '' or self.stock.price == 0 \
           or self.stock.quantity == 0:
            return False

        return True

    def match(self, req):
        return False

class Trade(object):
    ''' Information of a successfull trading.
    '''
    def __init__(self, buyer, seller, price, quantity):
        object.__init__(self)

        self.buyer = buyer
        self.seller = seller
        self.price = price
        self.quantity = quantity
        self.timestamp = timestamp

    def __str__(self):
        return '0' 
              

class Trader(threading.Thread):
    def __init__(self, name='Trader', target='Buy'):
        threading.Thread.__init__(self)

        self.name = name
        self.target = target
        self.tid = uuid.uuid4()     # Trader id

        self.stopped = True

        self.log = logging.getLogger("TRADER")
        self.log.debug("TRADER: Trader %d created" % (self.tid))

    def __str__(self):
        return self.name

    def start(self):
        self.stopped = False
        threading.Thread.start(self)

    def run(self):
        while not self.stopped:
            self.trade()

    def stop(self):
        self.stopped = True

    def trade(self):
        ''' Make buying or selling decisioins and post it to Stock Exchange.
        '''

        (action, stock) = self.decide()

        try:
            request = TradeRequest(self, action, stock)
        except TypeError, e:
            self.log.warning("TRADER: buy_stock: %s" % e)

        tries = 3
        for i in xrange(tries):
            # Sleep a random secs before make an bid
            #time.sleep(random.randint(TRADE_TIME_LOW, TRADE_TIME_HIGH))
            time.sleep(random.randint(1, 3))
            self.log.debug("TRADER: Trader %d buy stock, try %d" 
                           % (self.tid, i + 1))
            if not self.put_trade_request(request):
                self.log.debug("TRADER: Trader %d: Buy stock successed!!!" 
                               % (self.tid))
                return True
        self.log.warning("TRADER: Trader %d: Buy stock failed" % (self.tid))

        return False

    def put_trade_request(self, req=''):
        ''' Post request to Stock Exchange and retrieve response.
        '''
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            sock.connect((HOST, PORT))
        except socket.error, e:
            if e.errno != 106:      # If endpoint is in use, skip.
                self.log.warning("TRADER: Socket connect error: %s" % e)
                return False
        try:
            self.log.warning("TRADER: %s: Send request: %s" % (self, req))
            sock.send("%s" % (req))
            response = sock.recv(100)
            if response == TRADE_STATE_A:
                return True
            elif response == TRADE_STATE_S:
                return True
            elif response == TRADE_STATE_F:
                return False
            elif response == TRADE_STATE_W:
                return False
        except socket.error, e:
            self.log.warning("TRADER: Socket send/recv error: %s" % e)
        finally:
            sock.shutdown(socket.SHUT_RDWR)
            sock.close()
            del sock

        return False

    def get_trade_result(self):
        pass

    def decide(self):
        action = 'buy'
        s = stock.StockBase()

        return (action, s)

def main():
    FORMAT = "%(asctime)-15s %(message)s"
    logging.basicConfig(format=FORMAT)
    log = logging.getLogger("TRADER")
    log.setLevel(logging.DEBUG)
    log.warning("TRADER: Start Traders")

    random.seed(time.time())

    # Create a few Trader threads.
    trader = []
    trader_thread = []
    for x in xrange(TRADER_NUMBER):
        t = Trader()
        trader.append(t)
        th = threading.Thread(target=t.trade)
        trader_thread.append(th)
    for x in xrange(TRADER_NUMBER):
        trader_thread[x].start()
    for x in xrange(TRADER_NUMBER):
        trader_thread[x].join()

if __name__ == '__main__':
    main()

